package cn.achao.csr.system.service.impl;

import cn.achao.csr.api.SequenceApi;
import cn.achao.csr.api.model.dto.RegisterDTO;
import cn.achao.csr.api.model.entity.LoginUser;
import cn.achao.csr.api.model.entity.SysRole;
import cn.achao.csr.api.model.entity.SysUser;
import cn.achao.csr.api.model.entity.SysUserExpand;
import cn.achao.csr.base.constant.Constants;
import cn.achao.csr.base.constant.SecurityConstants;
import cn.achao.csr.base.constant.UserConstants;
import cn.achao.csr.base.constant.enums.RegisterTypeEnum;
import cn.achao.csr.base.constant.enums.SysSourceEnum;
import cn.achao.csr.base.constant.enums.ThirdAuthEnum;
import cn.achao.csr.base.exception.BusinessException;
import cn.achao.csr.base.resp.R;
import cn.achao.csr.base.utils.StringUtils;
import cn.achao.csr.base.utils.ThrowUtils;
import cn.achao.csr.datascope.annotation.DataScope;
import cn.achao.csr.security.utils.SecurityUtils;
import cn.achao.csr.system.dao.SysMenuDao;
import cn.achao.csr.system.dao.SysRoleDao;
import cn.achao.csr.system.dao.SysUserDao;
import cn.achao.csr.system.dao.SysUserExpandDao;
import cn.achao.csr.system.service.SysUserService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;

/**
 * @author achao
 * @description 针对表【sys_user(用户表)】的数据库操作Service实现
 * @createDate 2025-01-13 22:54:19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl implements SysUserService {

    private final SysUserDao userDao;
    private final SysUserExpandDao userExpandDao;
    private final SysRoleDao roleDao;
    private final SysMenuDao menuDao;

    private final SequenceApi sequenceApi;

    @Override
    @Transactional
    public SysUser register(RegisterDTO req) {
        verifyRegisterReq(req);
        SysUserExpand sysUserExpand = buildUserExpandByRegister(req);
        SysUser sysUser = buildUserByRegister(req, sysUserExpand.getId());
        // TODO 添加默认权限和角色

        userDao.save(sysUser);
        userExpandDao.save(sysUserExpand);
        return sysUser;
    }


    @Override
    public SysUser selectUserByUserAccount(String userAccount) {
        return userDao.selectUserByUserAccount(userAccount);
    }

    @Override
    public SysUser infoByZfbOpenId(String openId) {
        return userDao.selectUserByZfbOpenId(openId);
    }

    @Override
    public void getUserPermissions(LoginUser loginUser) {
        Set<String> perms = new HashSet<>();
        SysUser user = loginUser.getUser();
        if (user.isAdmin()) {
            perms.add("*:*:*");
        } else {
            List<SysRole> roles = user.getRoles();
            if (!CollectionUtils.isEmpty(roles)) {
                // 多角色设置permissions属性，以便数据权限匹配权限
                for (SysRole role : roles) {
                    if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL)) {
                        Set<String> rolePerms = menuDao.selectMenuPermsByRoleId(role.getId());
                        role.setPermissions(rolePerms);
                        perms.addAll(rolePerms);
                    }
                }
            } else {
                perms.addAll(menuDao.selectMenuPermsByUserId(user.getId()));
            }
        }
        loginUser.setPermissions(perms);
    }

    @Override
    public void getUserRoles(LoginUser loginUser) {
        Set<String> roles = new HashSet<>();
        roles.addAll(roleDao.selectRolePermissionByUserId(loginUser.getUserId()));
        loginUser.setRoles(roles);
    }

    @Override
    @Transactional
    public SysUser updateOpenId(String userAccount, String openId, String userInfo, ThirdAuthEnum thirdAuth) {
        SysUser sysUser = userDao.selectUserByUserAccount(userAccount);
        ThrowUtils.throwIf(sysUser == null,
                BusinessException.fail("用户账号不存在", SysSourceEnum.CSR_SYSTEM.getSysName()));
        SysUserExpand userExpand = sysUser.getUserExpand();
        ThrowUtils.throwIf(userExpand == null,
                BusinessException.fail("用户拓展信息异常,请联系管理员", SysSourceEnum.CSR_SYSTEM.getSysName()));

        if (ThirdAuthEnum.ZFB == thirdAuth) {
            userExpand.setZfbId(openId);
            userExpand.setZfbUserInfo(userInfo);
        }
        if (ThirdAuthEnum.WX == thirdAuth) {
            userExpand.setWxId(openId);
            userExpand.setWxUserInfo(userInfo);
        }


        boolean updateRes = userExpandDao.updateById(userExpand);
        return sysUser;
    }

    @Override
    public Boolean isExistOpenId(String openId, ThirdAuthEnum thirdAuthEnum) {
        if (ThirdAuthEnum.ZFB == thirdAuthEnum) {
            return userExpandDao.isExistZfbOpenId(openId);
        }

        if (ThirdAuthEnum.WX == thirdAuthEnum) {
            return userExpandDao.isExistWxOpenId(openId);
        }

        return false;

    }

    @Override
    public Map<Long, SysUser> getBatchByIds(List<Long> userIds) {
        return userDao.getBatchByIds(userIds);
    }

    /**
     * 校验注册请求
     * @param req
     */
    private void verifyRegisterReq(RegisterDTO req) {
        RegisterTypeEnum registerType = req.getRegisterType();
        String userAccount = req.getUserAccount();
        String userPwd = req.getUserPwd();
        String nickName = req.getNickName();
        String avatarUrl = req.getAvatarUrl();
        String accNbr = req.getAccNbr();
        String email = req.getEmail();
        String zfbOpenId = req.getZfbOpenId();
        String zfbUserInfo = req.getZfbUserInfo();
        String wxOpenId = req.getWxOpenId();
        String wxUserInfo = req.getWxUserInfo();
        if (registerType == RegisterTypeEnum.NORMAL) {
            ThrowUtils.throwIf(StringUtils.isAnyBlank(userPwd),
                    BusinessException.fail("参数异常", SysSourceEnum.CSR_SYSTEM.getSysName()));
        }
        if (registerType == RegisterTypeEnum.ZFB) {
            ThrowUtils.throwIf(StringUtils.isAnyBlank(zfbOpenId, zfbUserInfo),
                    BusinessException.fail("参数异常", SysSourceEnum.CSR_SYSTEM.getSysName()));
        }

        if (registerType == RegisterTypeEnum.WX) {
            ThrowUtils.throwIf(StringUtils.isAnyBlank(wxOpenId, wxUserInfo),
                    BusinessException.fail("参数异常", SysSourceEnum.CSR_SYSTEM.getSysName()));
        }

        if (registerType == RegisterTypeEnum.PHONE) {
            ThrowUtils.throwIf(StringUtils.isAnyBlank(accNbr, userPwd),
                    BusinessException.fail("参数异常", SysSourceEnum.CSR_SYSTEM.getSysName()));
        }

        if (registerType == RegisterTypeEnum.EMAIL) {
            ThrowUtils.throwIf(StringUtils.isAnyBlank(email, userPwd),
                    BusinessException.fail("参数异常", SysSourceEnum.CSR_SYSTEM.getSysName()));
        }

        if (StringUtils.isNotBlank(userAccount)) {
            ThrowUtils.throwIf(userDao.isExistAccount(userAccount),
                    BusinessException.fail("用户账号已存在", SysSourceEnum.CSR_SYSTEM.getSysName()));
        }
    }

    /**
     * 构建注册用户拓展信息
     * @param req
     * @return
     */
    private SysUserExpand buildUserExpandByRegister(RegisterDTO req) {
        SysUserExpand userExpand = new SysUserExpand(true);
        RegisterTypeEnum registerType = req.getRegisterType();
        if (registerType == RegisterTypeEnum.ZFB) {
            String openId = req.getZfbOpenId();
            String userInfo = req.getZfbUserInfo();
            userExpand.setZfbId(openId);
            userExpand.setZfbUserInfo(userInfo);
        }

        if (registerType == RegisterTypeEnum.WX) {
            String openId = req.getWxOpenId();
            String userInfo = req.getWxUserInfo();
            userExpand.setWxId(openId);
            userExpand.setWxUserInfo(userInfo);
        }

        return userExpand;
    }

    /**
     * 构建注册用户信息
     * @param req
     * @return
     */
    private SysUser buildUserByRegister(RegisterDTO req, Long userExpandId) {
        String nickName = req.getNickName();
        String userAccount = req.getUserAccount();
        String userPwd = req.getUserPwd();
        String username = SecurityUtils.getUsername();
        Long userId = SecurityUtils.getUserId();
        String createBy = SecurityConstants.DEFAULT_USER;
        if (StringUtils.isNotBlank(username) && userId != null) {
            createBy = username + "-" + userId;
        }
        if (StringUtils.isBlank(userAccount)) {
            Long segmentId = sequenceApi.getSegmentId("csr_user_account", SecurityConstants.INNER);
            userAccount = Constants.PROJECT_NAME + segmentId;
        }
        if (StringUtils.isBlank(userPwd)) {
            // 随机生成8位
            userPwd = RandomUtil.randomString(8);
        }
        LocalDateTime now = LocalDateTime.now();
        SysUser sysUser = BeanUtil.copyProperties(req, SysUser.class);
        sysUser.setUserAccount(userAccount);
        sysUser.setNickName(nickName);
        sysUser.setExpandId(userExpandId);
        sysUser.setCreateTime(now);
        sysUser.setUpdateTime(now);
        sysUser.setUserPwd(SecurityUtils.encryptPassword(userPwd));
        sysUser.setCreateBy(createBy);
        sysUser.setUpdateBy(createBy);
        return sysUser;
    }
}




